package com.plugin.uniapp.utils;

import android.os.Handler;
import android.os.Looper;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

public class WebSocketClient {
    public interface OpenCallback {
        void onOpen();
    }

    public interface BytesCallback {
        void onMessage(byte[] data);
    }

    public interface TextCallback {
        void onMessage(String text);
    }

    public interface CloseCallback {
        void onClose();
    }

    private List<BytesCallback> bytesCallbacks = new ArrayList<>();
    private List<TextCallback> textCallbacks = new ArrayList<>();
    private List<CloseCallback> closeCallbacks = new ArrayList<>();
    public boolean isConnected = false;
    public String url;
    private OpenCallback currOpenCallback;
    private OkHttpClient client;
    private WebSocket socket;
    private Handler handler = new Handler(Looper.getMainLooper());
    private boolean canAutoReconnect = false;
    private static final long RECONNECT_DELAY = 3000; // 5秒重连
    private boolean forVideoStream;

    // 初始化WebSocket连接
    public void connect(String url, OpenCallback onOpenCallback, boolean forVideoStream) {
        this.url = url;
        this.currOpenCallback = onOpenCallback;
        this.forVideoStream = forVideoStream;
        this.canAutoReconnect = true;
        final OpenCallback _onOpenCallback = this.currOpenCallback;
        log("WebSocket开始连接：" + url + " forVideoStream:" + forVideoStream, false);
        client = new OkHttpClient.Builder().pingInterval(30, TimeUnit.SECONDS).build();
        socket = client.newWebSocket(new Request.Builder().url(url).build(), new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                log("WebSocket连接成功：" + url, false);
                isConnected = true;
                handler.post(() -> {
                    if (_onOpenCallback != null) {
                        _onOpenCallback.onOpen();
                    }
                });
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                handler.post(() -> {
                    if (text.contains("{")) {
                        log("收到Json消息: " + text, true);
                        for (TextCallback onCallback : textCallbacks) {
                            onCallback.onMessage(text);
                        }
                    } else {
                        //log("收到非JSON消息: " + text, true);
                    }
                });
            }

            @Override
            public void onMessage(WebSocket webSocket, ByteString bytes) {
                if (!forVideoStream) {
                    log("收到字节消息: " + bytes.size(), true);
                }
                handler.post(() -> {
                    for (BytesCallback onCallback : bytesCallbacks) {
                        onCallback.onMessage(bytes.toByteArray());
                    }
                });
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                webSocket.close(1000, null);
                isConnected = false;
                socket = null;
            }

            @Override
            public void onClosed(WebSocket webSocket, int code, String reason) {
                log("连接已关闭: " + url, false);
                handler.post(() -> {
                    for (CloseCallback onCallback : closeCallbacks) {
                        onCallback.onClose();
                    }
                });
                isConnected = false;
                socket = null;
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                error("连接失败[" + url + "]: " + t.getMessage(), true);
                handler.postDelayed(() -> {
                    if (canAutoReconnect) {
                        log("尝试重新连接...", true);
                        reconnect();
                    }
                }, RECONNECT_DELAY);
            }
        });
    }

    public void addBytesCallback(BytesCallback callback) {
        bytesCallbacks.add(callback);
    }

    public void removeBytesCallback(BytesCallback callback) {
        bytesCallbacks.remove(callback);
    }

    public void addTextCallback(TextCallback callback) {
        textCallbacks.add(callback);
    }

    public void removeTextCallback(TextCallback callback) {
        textCallbacks.remove(callback);
    }

    public void addCloseCallback(CloseCallback callback) {
        closeCallbacks.add(callback);
    }

    public void removeCloseCallback(CloseCallback callback) {
        closeCallbacks.remove(callback);
    }

    // 发送消息
    public void sendMessage(String message) {
        if (socket != null && isConnected) {
            log("发送消息: " + message, true);
            socket.send(message);
        } else {
            error("发送消息: " + message + " WebSocket未连接", true);
        }
    }

    public void sendMessage(ByteString bytes) {
        if (socket != null && isConnected) {
            log("发送消息 bytes.size():" + bytes.size(), true);
            socket.send(bytes);
        } else {
            error("发送消息 bytes.size():" + bytes.size() + " WebSocket未连接", true);
        }
    }

    public void disconnect() {
        if (!isConnected) return;
        log("主动断开WebSocket：" + url, false);
        canAutoReconnect = false;
        isConnected = false;
        try {
            if (socket != null) {
                socket.close(1000, "正常关闭");
                socket = null;
            }
            if (client != null) {
                client.dispatcher().executorService().shutdown();
            }
            handler.removeCallbacksAndMessages(null);
        } catch (Exception e) {
            error(e.toString(), false);
        }
    }

    // 断线重连
    public void reconnect() {
        connect(socket.request().url().toString(), currOpenCallback, forVideoStream);
    }

    private void log(String msg, boolean logToScreen) {
        if (forVideoStream) return;
        Logger.log(msg, getClass(), logToScreen);
    }

    private void error(String msg, boolean logToScreen) {
        if (forVideoStream) return;
        Logger.error(msg, getClass(), logToScreen);
    }
}